package net.vinote.sosa.rpc;

import java.net.SocketTimeoutException;
import java.util.Map;

public abstract class AbstractSession implements Session {
	/** 上一次访问时间 */
	private long lastAccessTime;
	/** 最长闲置时间 */
	protected int maxInactiveInterval;
	/** 失效标识 */
	protected boolean invalidated = false;
	/** 当前会话唯一标识 */
	protected String sessionId = null;
	protected long timeout;
	protected Map<String, Object> synchRespMap;

	@Override
	public final boolean notifySyncMessage(RpcResponse reponse) {

		Object reqMsg = synchRespMap.get(reponse.getUuid());
		if (reqMsg != null) {
			synchronized (reqMsg) {
				if (synchRespMap.containsKey(reponse.getUuid())) {
					synchRespMap.put(reponse.getUuid(), reponse);
					reqMsg.notifyAll();
					return true;
				}
			}
		}
		return false;

	}
	@Override
	public final void sendResponse(RpcResponse response) throws Exception {
		//System.out.println(response);
		write0(response);
	}
	@Override
	public final RpcResponse sendRpcRequest(RpcRequest request) throws Exception {
		return sendRpcRequest(request, timeout);
	}
	@Override
	public final RpcResponse sendRpcRequest(RpcRequest request, long timeout) throws Exception {
		synchRespMap.put(request.getUuid(), request);
		write0(request);
		if (synchRespMap.containsKey(request.getUuid()) && synchRespMap.get(request.getUuid()) == request) {
			synchronized (request) {
				if (synchRespMap.containsKey(request.getUuid()) && synchRespMap.get(request.getUuid()) == request) {
					try {
						request.wait(timeout);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
		Object resp = null;
		synchronized (request) {
			resp = synchRespMap.remove(request.getUuid());
		}
		if (resp == null || resp == request) {
			throw new SocketTimeoutException("Message is timeout!" + resp);
		}
		if (resp instanceof RpcResponse) {
			return (RpcResponse) resp;
		}
		throw new RuntimeException("invalid response " + resp);
	}
	
	public final void invalidate(boolean immediate) {

		invalidated = true;
		for (Object unit : synchRespMap.values()) {
			synchronized (unit) {
				unit.notifyAll();
			}
		}
		//attributeMap.clear();
		close();
	}
	@Override
	public final int getMaxInactiveInterval() {
		return maxInactiveInterval;
	}

	public final long getLastAccessedTime() {
		return lastAccessTime;
	}

	public final boolean isInvalid() {
		return invalidated;
	}

	public final String getId() {
		refreshAccessedTime();
		return sessionId;
	}

	public final void invalidate() {
		invalidate(true);
	}

	public final void refreshAccessedTime() {
		lastAccessTime = System.currentTimeMillis();
	}

	/**
	 * Getter method for property <tt>timeout</tt>.
	 *
	 * @return property value of timeout
	 */
	public final long getTimeout() {
		return timeout;
	}

	public void setMaxInactiveInterval(int interval) {
		refreshAccessedTime();
		maxInactiveInterval = interval;
	}
	protected abstract <T> void write0(T t) throws Exception;
}
